package com.molichuxing.gateway.bff.permission.services.impl;

import com.alibaba.fastjson.JSONObject;
import com.moli.iov.util.Md5PwdEncoder;
import com.moli.iov.util.api.ApiUtils;
import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.result.ResponseResult;
import com.molichuxing.framework.utils.*;
import com.molichuxing.gateway.bff.permission.convertor.Convert;
import com.molichuxing.gateway.bff.permission.entity.request.AccountCreateVo;
import com.molichuxing.gateway.bff.permission.entity.request.AccountModifyVo;
import com.molichuxing.gateway.bff.permission.entity.request.ModifyPassowrdVo;
import com.molichuxing.gateway.bff.permission.entity.response.AccountLoginVo;
import com.molichuxing.gateway.bff.permission.entity.response.AccountVo;
import com.molichuxing.gateway.bff.permission.services.AccountBffService;
import com.molichuxing.gateway.property.EmailSubjectEnum;
import com.molichuxing.gateway.utils.DealerEmailUtil;
import com.molichuxing.gateway.utils.RequestAttrUtil;
import com.molichuxing.gateway.utils.SSOTokenUtil;
import com.molichuxing.gateway.utils.TokenUtil;
import com.molichuxing.gateway.utils.entity.DealerEntity;
import com.molichuxing.gateway.utils.entity.UserEntity;
import com.molichuxing.services.business.dto.response.AccountLoginBizDto;
import com.molichuxing.services.business.service.AccountBizService;
import com.molichuxing.services.business.service.SmsBizService;
import com.molichuxing.services.exception.PermissionExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.request.create.IpDetail;
import com.molichuxing.services.infrastructure.dto.response.DealerDto;
import com.molichuxing.services.infrastructure.dto.response.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.DealerStatusEnum;
import com.molichuxing.services.property.LoginLogTypeEnum;
import com.molichuxing.services.property.SmsTemplateEnum;
import com.molichuxing.services.property.SystemTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service("permissionBffService")
public class AccountBffServiceImpl implements AccountBffService {
    private static final Logger logger = LoggerFactory.getLogger(AccountBffServiceImpl.class);

    @Resource
    private TokenUtil tokenUtil;

    @Resource
    private SSOTokenUtil ssoTokenUtil;

    @Resource
    private AccountBizService accountBizService;

    @Resource
    private IpService ipService;

    @Resource
    private AccountService accountService;

    @Resource
    private AccountGroupService accountGroupService;

    @Resource
    private DealerService dealerService;

    @Resource
    private AccountDealerService accountDealerService;

    @Value("${password.salt}")
    private String PASSWORD_SALT;

    @Resource
    private SmsBizService smsBizService;

    @Resource
    private DealerEmailUtil emailUtil;

    @Resource
    private LoginLogService loginLogService;

    @Value("${profiles.active.explain}")
    private String active;
    /**
     * 账号登录
     *
     * @param params account：账号 <br/>
     *               password：密码 <br/>
     *               systemType：系统类型-enum <br/>
     * @return
     * @throws BizException
     * @throws Exception
     */
    @Override
    public AccountLoginVo login(Map<String, Object> params) throws BizException, Exception {
        AccountLoginVo result = null;
        // 登录
        String requestIp = IpUtil.getIpAddr(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
        params.put("requestIp", requestIp); //请求者ip

        //获取地址
        StringBuffer ipAddress = new StringBuffer();
        try {
            IpDetail ipDetail = ipService.getIpDetail(requestIp);
            if (ipDetail != null) {
                String country = ipDetail.getCountry() == null ? "" : ipDetail.getCountry(); //国家
                String region = ipDetail.getRegion() == null ? "" : ipDetail.getRegion(); //省份、直辖市
                String city = ipDetail.getCity() == null ? "" : ipDetail.getCity(); //城市
                ipAddress.append(country);
                ipAddress.append(region);
                ipAddress.append(!region.equals(city) ? city : "");
            }
        } catch (Exception e) {
            logger.error("根据ip获取地址异常");
            logger.error(e.getMessage(), e);
        }

        params.put("requestIpAddress", ipAddress.toString()); //请求者ip所属地

        AccountLoginBizDto accountLoginBizDto = accountBizService.login(params);

        String ssoToken = ssoTokenUtil.generateSsoTokenAndHead(accountLoginBizDto.getAccount());

        UserEntity user = Convert.toUserEntity(accountLoginBizDto);
        user.setSsoToken(ssoToken);

        DealerDto dealerDto = dealerService.getDealerById(accountLoginBizDto.getDealerId());
        if (dealerDto == null) {
            logger.error("登陆失败，经销商为空，用户id ::{}, dealer ::{}", user.getAccountId(), dealerDto);
            throw new BizException(PermissionExceptionCodeEnum.DISABLE.getCode(),
                    PermissionExceptionCodeEnum.DISABLE.getMessage());
        }
        if (dealerDto.getStatus() == DealerStatusEnum.CLOSE.getValue()) {
            logger.error("登陆失败，经销商状态为终止合作，用户id ::{}, dealer ::{}", user.getAccountId(), dealerDto);
			throw new BizException(PermissionExceptionCodeEnum.DISABLE.getCode(),
                    PermissionExceptionCodeEnum.DISABLE.getMessage());        
		}

        DealerEntity dealer = com.molichuxing.gateway.bff.dealer.convertor.Convert.toDealerEntity(dealerDto);
        user.setDealer(dealer);

        // 删除redis中存在的该账户信息
        tokenUtil.deleteAll(user);
        // 生成本地token，保存redis
        tokenUtil.setUserToken(user);



        //生成单点登陆token，直接返回

        result = Convert.toAccountLoginVo(accountLoginBizDto);
        result.setToken(ssoToken);
        result.setDealer(dealer);
        result.setLoginIp(requestIp);
        result.setLoginArea(ipAddress.toString());

        return result;
    }

    @Override
    public Paged<AccountVo> getAccountList(Map<String, Object> param, int pageNum, int pageSize) {
        param.put("systemType", SystemTypeEnum.DEALER.getValue());
        Paged<AccountDto> pageList = accountBizService.getAccountListByDealer(param, pageNum, pageSize);
        Paged<AccountVo> result = new Paged<>();
        if (pageList != null) {
            List<AccountDto> dataList = pageList.getList();

            final List<AccountVo> resultDataList = new ArrayList<AccountVo>();
            if (CollectionUtils.isNotEmpty(dataList)) {
                //1
                final List<Integer> accountIdList = new ArrayList<>();
                dataList.forEach(account -> {
                    accountIdList.add(account.getId());
                    resultDataList.add(Convert.toAccountVo(account));
                });

                //2
                final Map<Integer, DealerDto> accountBindDealerMap = new HashMap<>();
                Map<String, Object> getAccountDealerParam = new HashMap<>();
                getAccountDealerParam.put("accountIds", accountIdList);
                List<AccountDealerDto> accountDealerList = accountDealerService.getAccountDealerByParam(getAccountDealerParam);
                if (CollectionUtils.isNotEmpty(accountDealerList)) {

                    final List<Integer> dealerIdList = new ArrayList<>();
                    accountDealerList.forEach(accountDealer -> {
                        if (accountDealer.getDealerId() != null && accountDealer.getDealerId() > 0) {
                            dealerIdList.add(accountDealer.getDealerId());
                        }
                    });

                    Map<Integer, DealerDto> dealerMap = null;
                    if (CollectionUtils.isNotEmpty(dealerIdList)) {
                        Map<String, Object> getDealerParam = new HashMap<>();
                        getDealerParam.put("dealerIds", dealerIdList);
                        List<DealerDto> dealerList = dealerService.getDealerListByParam(getDealerParam);
                        if (CollectionUtils.isNotEmpty(dealerList)) {
                            dealerMap = dealerList.stream().collect(Collectors.toMap(DealerDto::getDealerId, dealerDto -> dealerDto));
                        }
                    }

                    if (dealerMap != null && dealerMap.size() > 0) {
                        for (AccountDealerDto accountDealer : accountDealerList) {
                            DealerDto dto = null;
                            if ((dto = dealerMap.get(accountDealer.getDealerId())) != null) {
                                accountBindDealerMap.put(accountDealer.getAccountId(), dealerMap.get(accountDealer.getDealerId()));
                            }
                        }
                    }
                }

                resultDataList.forEach(accountVo -> {
                    DealerDto dto = null;
                    if ((dto = accountBindDealerMap.get(accountVo.getId())) != null) {
                        accountVo.setDealerId(dto.getDealerId());
                        accountVo.setDealerName(dto.getShortName());
                    }

                });
            }
            result.setList(resultDataList);
            result.setTotal(pageList.getTotal());
            result.setPageSize(pageList.getPageSize());
        }

        return result;
    }


    @Override
    @Transactional
    public ResponseResult<Boolean> createAccount(AccountCreateVo newAccount) {
        ResponseResult<Boolean> result = validateCreateParam(newAccount);
        if (result != null) {
            return result;
        }
        result = new ResponseResult<>();

        try {
            //查询账号是否存在
            Map<String, Object> getAccountCountParam = new HashMap<>();
            getAccountCountParam.put("account", newAccount.getAccount());
            getAccountCountParam.put("systemType", SystemTypeEnum.DEALER.getValue());
            int count = accountService.getAccountCount(getAccountCountParam);
            if (count > 0) {
                logger.error("用户已经存在，无法重复保存，account is :: {}", newAccount.getAccount());
                return result.error("保存失败，用户[" + newAccount.getAccount() + "]已经存在");
            }

            UserEntity currentLoginUser = tokenUtil.getUser();

            String password = ApiUtils.generateNonceStrLower(8);
            AccountCreateDto accountDto = Convert.toAccountCreateDto(newAccount);
            accountDto.setPassword(Md5PwdEncoder.encodePassword(password, PASSWORD_SALT));
            accountDto.setAccountId(currentLoginUser.getAccountId()); //操作人名字
            accountDto.setAccountAccount(currentLoginUser.getRealName()); //操作人id
            accountDto.setPasswordSalt(PASSWORD_SALT);
            int accountId = accountService.createAccount(accountDto);
            if (accountId > 0) {
                //绑定用户与角色的关联关系
                if (newAccount.getGroupId() != null && newAccount.getGroupId() > 0) {
                    AccountGroupDto accountGroup = new AccountGroupDto();
                    accountGroup.setAccountId(accountId);
                    accountGroup.setGroupId(newAccount.getGroupId());
                    accountGroup.setGmtCreate(LocalDateTime.now());
                    accountGroupService.createBatchAccountGroup(accountGroup);
                }

                Integer dealerId = RequestAttrUtil.getCurrentDealerId(); //当前登陆用户的经销商id

                //添加数据到经销商关联关系表
                AccountDealerDto accountDealer = new AccountDealerDto();
                accountDealer.setAccountId(accountId);
                accountDealer.setDealerId(dealerId);
                accountDealerService.createAccountDealer(accountDealer);

                //发送短信，发送邮件
                String emailContent = emailUtil.editorCreateAccountSuccessContent(newAccount.getAccount(), password); //发送邮件
                boolean sendResult = emailUtil.send(EmailSubjectEnum.CREATE_DEALER_ACCOUNT_SUCCESS.getName(), emailContent, newAccount.getAccount());
                if (!sendResult) {
                    String errorEmailContent = emailUtil.editorCreateAccountErrorContent(newAccount.getRealName());
                    boolean errorEmailResult = emailUtil.send(newAccount.getRealName() + EmailSubjectEnum.CREATE_ACCOUNT_ERROR.getName(), errorEmailContent, currentLoginUser.getAccount());
                    if (!errorEmailResult) {
                        String dingdingContent = active + "用户【" + newAccount.getAccount() + "】创建成功，发送短信、邮件失败,操作人手机号【" + currentLoginUser.getUserPhone()+ "】";
                        DingTalkUtil.exceptionSend(dingdingContent);
                    }
                } else {
                    smsBizService.sendMessage(newAccount.getUserPhone(), SmsTemplateEnum.CREATE_DEALER_ACCOUNT_SUCCESS.getValue(), null, null); //发送短信
                }

                return result.success("成功", true);
            } else {
                return result.error("保存失败", false);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return result.error("保存失败");
    }

    @Override
    public ResponseResult<Boolean> modifyAccount(AccountModifyVo account) {
        ResponseResult<Boolean> result = validateModifyParam(account);
        if (result != null) {
            return result;
        }
        result = new ResponseResult<>();

        try {
            //查询账号是否存在
            AccountDto oldAccount = accountService.getById(account.getId());
            if (oldAccount == null)
                return result.error("修改失败，当前用户不存在", Boolean.FALSE);

            AccountModifyDto accountDto = Convert.toAccountModifyDto(account);

            String password = "";
            if ((oldAccount.getAccount() == null  && !StringUtil.isEmpty(account.getAccount())) || (!oldAccount.getAccount().equals(account.getAccount()))) { //修改了邮箱
                //重新生成密码
                password = ApiUtils.generateNonceStrLower(8);
                accountDto.setPassword(Md5PwdEncoder.encodePassword(password, PASSWORD_SALT));

                Map<String, Object> getAccountCountParam = new HashMap<>();
                getAccountCountParam.put("account", account.getAccount());
                getAccountCountParam.put("systemType", SystemTypeEnum.DEALER.getValue());
                int count = accountService.getAccountCount(getAccountCountParam);
                if (count > 0) {
                    logger.error("用户已经存在，无法重复保存，account is :: {}", account.getAccount());
                    return result.error("保存失败，用户[" + account.getAccount() + "]已经存在", Boolean.FALSE);
                }
            }

            UserEntity currentLoginUser = tokenUtil.getUser();

            accountDto.setAccountId(currentLoginUser.getAccountId()); //操作人id
            accountDto.setAccountAccount(currentLoginUser.getRealName()); //操作人名字
            accountBizService.modifyAccount(accountDto);
            //判断前后绑定角色是否一致，不一致则根据用户删除再添加
            if (account.getGroupId() != null && account.getGroupId() > 0 && !oldAccount.getIsSuper()) {
                accountGroupService.deleteByAccountId(account.getId()); //删除

                AccountGroupDto accountGroup = new AccountGroupDto();
                accountGroup.setAccountId(account.getId());
                accountGroup.setGroupId(account.getGroupId());
                accountGroup.setGmtCreate(LocalDateTime.now());
                accountGroupService.createBatchAccountGroup(accountGroup); //添加
            }

            if (!StringUtil.isEmpty(oldAccount.getAccount())) {
                tokenUtil.deleteUserByAccount(oldAccount.getAccount()); //强制登出
            }

            if ((oldAccount.getAccount() == null  && !StringUtil.isEmpty(account.getAccount())) || (!oldAccount.getAccount().equals(account.getAccount()))) { //修改了邮箱，发送短信，邮件
                JSONObject jsonObj = new JSONObject();
                jsonObj.put("useremail", account.getAccount());

                String emailContent = emailUtil.editorCreateAccountSuccessContent(account.getAccount(), password);
                boolean sendResult = emailUtil.send(EmailSubjectEnum.CREATE_DEALER_ACCOUNT_SUCCESS.getName(), emailContent, account.getAccount());
                smsBizService.sendMessage(account.getUserPhone(), SmsTemplateEnum.MODIFY_DEALER_ACCOUNT_SUCCESS.getValue(), jsonObj.toString(), null); //发送短信
            }
            result.setData(Boolean.TRUE);
            return result.success("成功", true);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return result.error("修改失败");
    }

    /**
     * 验证参数
     *
     * @param newAccount
     * @return
     */
    private ResponseResult<Boolean> validateCreateParam(AccountCreateVo newAccount) {

        ResponseResult<Boolean> result = new ResponseResult<>();
        result.setData(Boolean.FALSE);
        if (newAccount == null) {
            logger.error("添加用户失败，用户为null，create account is :: {}", newAccount);
            return result.error("添加用户失败", Boolean.FALSE);
        }

        if (StringUtil.isEmpty(newAccount.getAccount()))
            return result.error("添加用户失败，邮箱不能为空", Boolean.FALSE);
        if (!ValidateUtil.isValidEmail(newAccount.getAccount()))
            return result.error("添加用户失败，邮箱格式错误", Boolean.FALSE);
        if (StringUtil.isEmpty(newAccount.getRealName()))
            return result.error("添加用户失败，真实姓名不能为空", Boolean.FALSE);
        if (StringUtil.isEmpty(newAccount.getUserPhone()))
            return result.error("添加用户失败，手机号不能为空", Boolean.FALSE);
        if (newAccount.getUserPhone().length() < 11 || newAccount.getUserPhone().length() > 11)
            return result.error("添加用户失败，手机号格式错误", Boolean.FALSE);

        return null;
    }

    /**
     * 验证参数
     *
     * @param account
     * @return
     */
    private ResponseResult<Boolean> validateModifyParam(AccountModifyVo account) {

        ResponseResult<Boolean> result = new ResponseResult<>();
        result.setData(Boolean.FALSE);
        if (account == null) {
            logger.error("修改用户失败，用户为null，modify account is :: {}", account);
            return result.error("修改用户失败", Boolean.FALSE);
        }

        if (StringUtil.isEmpty(account.getAccount()))
            return result.error("修改用户失败，邮箱不能为空", Boolean.FALSE);
        if (!ValidateUtil.isValidEmail(account.getAccount()))
            return result.error("修改用户失败，邮箱格式错误", Boolean.FALSE);
        if (StringUtil.isEmpty(account.getRealName()))
            return result.error("修改用户失败，真实姓名不能为空", Boolean.FALSE);
        if (StringUtil.isEmpty(account.getUserPhone()))
            return result.error("修改用户失败，手机号不能为空", Boolean.FALSE);
        if (account.getUserPhone().length() < 11 || account.getUserPhone().length() > 11)
            return result.error("修改用户失败，手机号格式错误", Boolean.FALSE);
        if (account.getId() <= 0)
            return result.error("修改用户失败，用户id不能为空", Boolean.FALSE);

        return null;
    }

    @Override
    public ResponseResult<Boolean> modifyResetPassword(AccountModifyVo vo) {

        ResponseResult<Boolean> result = new ResponseResult<>();
        result.setData(Boolean.FALSE);

        if (vo == null)
            return result.error("参数不能为空");
        if (vo.getId() <= 0)
            return result.error("ID不能为空");

        UserEntity currentLoginUser = tokenUtil.getUser();
        try {
            AccountDto account = accountService.getById(vo.getId());
            if (account == null)
                return result.error("用户不存在");

            String password = ApiUtils.generateNonceStrLower(8);
            account.setPassword(Md5PwdEncoder.encodePassword(password, PASSWORD_SALT));
            account.setAccountId(currentLoginUser.getAccountId()); //操作人id
            account.setAccountAccount(currentLoginUser.getRealName()); //操作人名字
            accountService.modifyAccount(account);

            tokenUtil.deleteUserByAccount(account.getAccount()); //强制登出
//          发送邮件
            String content = emailUtil.editorResetPasswordContent(account.getAccount(), password);
            boolean sendResult = emailUtil.send(EmailSubjectEnum.RESET_PASSWORD.getName(), content, account.getAccount());
            if (sendResult)
                smsBizService.sendMessage(account.getUserPhone(), SmsTemplateEnum.RESET_PASSWORD_BY_DEALER.getValue(), null, null); // 发送短信
            return result.success("修改成功", Boolean.TRUE);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return result.error("修改失败");
    }

    @Override
    public ResponseResult<Boolean> modifyPassword(ModifyPassowrdVo vo) {
        ResponseResult<Boolean> result = new ResponseResult<Boolean>();

        if (vo == null)
            return result.error("参数不能为空", Boolean.FALSE);

        UserEntity user = tokenUtil.getUser();
        if (user != null) {
            int id = user.getAccountId();
            String oldPassword = vo.getOldPassword();
            String newPassword = vo.getNewPassword();

            if (StringUtil.isEmpty(oldPassword))
                return result.error("原密码不能为空", Boolean.FALSE);
            if (StringUtil.isEmpty(newPassword))
                return result.error("新密码不能为空", Boolean.FALSE);

            oldPassword = Md5PwdEncoder.encodePassword(new String(Base64Utils.decodeFromString(oldPassword)), PASSWORD_SALT);
            newPassword = Md5PwdEncoder.encodePassword(new String(Base64Utils.decodeFromString(newPassword)), PASSWORD_SALT);


            AccountDto account = accountService.getById(id);
            if (!oldPassword.equals(account.getPassword()))
                return result.error("原密码错误，请重新录入", Boolean.FALSE);

            int row = accountService.modifyPassword(newPassword, id);
            if (row > 0) {
                tokenUtil.deleteUserByAccount(account.getAccount());
                return result.success("成功", Boolean.TRUE);
            }
        }

        return result.error("失败", Boolean.FALSE);
    }

    @Override
    public void logOut() {
        UserEntity user = tokenUtil.getUser(); //当前登录用户
        if (user != null) {
            try {
                List<LoginLogDto> logOutLogList = loginLogService.getLogByAccountAndType(user.getAccount(), LoginLogTypeEnum.LOGOUT.getValue());
                if (CollectionUtils.isNotEmpty(logOutLogList)) { //更新
                    loginLogService.updateAccountLogOutTime(user.getAccount());
                } else { //添加
                    LoginLogDto log = new LoginLogDto();
                    log.setAccountId(user.getAccountId());
                    log.setAccountName(user.getAccount());
                    log.setGroupId(user.getGroupId());
                    log.setGroupName(user.getGroupName());
                    log.setLoginTime(LocalDateTime.now());
                    log.setType(LoginLogTypeEnum.LOGOUT.getValue());
                    loginLogService.createLoginLog(log);
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            tokenUtil.deleteCurrentUser();
        }

    }
}
